﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AmiEmuLib.Configuration;
using System.Reflection;
using System.Xml;
using System.Diagnostics;
using AmiEmuLib.AmigaConfiguration;
using AmiEmuLib.AmigaConfiguration.MemoryConfig;

namespace AmiEmuLib.AmigaMachine.AmigaMemory
{
    /// <summary>
    /// Represent 64KB memory area.
    /// </summary>
    [DebuggerDisplay("{Type}, Address = {Address}")]
    public abstract class MemoryBank
    {
        /// <summary>
        /// Start address of memory in bank.
        /// </summary>
        public readonly uint Address;

        /// <summary>
        /// Memory.
        /// </summary>
        public readonly Memory Memory;

        /// <summary>
        /// Bank type;
        /// </summary>
        public readonly MemoryBankType Type;

        /// <summary>
        /// CPU exclusive memory.
        /// </summary>
        public  readonly bool Fast;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="a_address"></param>
        /// <param name="a_memory"></param>
        /// <param name="a_type,"></param>
        /// <param name="a_fast"></param>
        public MemoryBank(uint a_address, Memory a_memory, MemoryBankType a_type, bool a_fast)
        {
            Type = a_type;
            Address = a_address;
            Memory = a_memory;
            Fast = a_fast;
        }

        /// <summary>
        /// Address of last word (cell) in bank.
        /// </summary>
        public uint LastWordAddress
        {
            get
            {
                return Address + Consts.BANK_SIZE - 2;
            }
        }

        /// <summary>
        /// Get offset in bank.
        /// </summary>
        /// <param name="a_address"></param>
        /// <returns></returns>
        protected uint GetOffset(uint a_address)
        {
            return (a_address & Consts.BANK_MASK) / 2;
        }

        /// <summary>
        /// Is byte address belong to bank.
        /// </summary>
        /// <param name="a_address"></param>
        /// <returns></returns>
        public bool InRange(uint a_address)
        {
            return (a_address >= Address) && ((a_address - Address) < Consts.BANK_SIZE);
        }

        /// <summary>
        /// Reset bank memory to power-un state.
        /// </summary>
        internal abstract void Reset();

        /// <summary>
        /// Get memory byte from address.
        /// </summary>
        /// <param name="a_address"></param>
        /// <returns></returns>
        public abstract byte GetByte(uint a_address);

        /// <summary>
        /// Set memory byte in address.
        /// </summary>
        /// <param name="a_address"></param>
        /// <param name="a_value"></param>
        public abstract void SetByte(uint a_address, byte a_value);

        /// <summary>
        /// Get memory word from address.
        /// </summary>
        /// <param name="a_address"></param>
        /// <returns></returns>
        public abstract ushort GetWord(uint a_address);

        /// <summary>
        /// Set memory word in address.
        /// </summary>
        /// <param name="a_address"></param>
        /// <param name="a_value"></param>
        public abstract void SetWord(uint a_address, ushort a_value);

        /// <summary>
        /// Get memory long from address.
        /// </summary>
        /// <param name="a_address"></param>
        /// <returns></returns>
        public abstract uint GetLong(uint a_address);

        /// <summary>
        /// Set memory long in address.
        /// </summary>
        /// <param name="a_address"></param>
        /// <param name="a_value"></param>
        public abstract void SetLong(uint a_address, uint a_value);
    }
}
